package com.ncmem.up6.model;
import com.aliyun.oss.model.PartETag;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.ncmem.up6.utils.ConfigReader;
import com.ncmem.up6.utils.PathTool;
import com.ncmem.up6.biz.FileEtag;
import com.ncmem.up6.biz.FolderSchema;
import com.ncmem.up6.store.StorageType;
import com.obs.services.model.PartEtag;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.*;
import java.util.*;

/**
 * 原型
 * 更新记录：
 * 	2016-01-07
 * 		FileMD5更名为md5
 * 		PostComplete更名为complete
 * 		FileLength更名为lenLoc
 * 		FileSize更名为sizeLoc
 * 		PostedPercent更名为perSvr
 * Created by jmzy on 2021/1/5.
 */
@Data
@Document("up6_files")
public class FileInf implements Serializable{

    public static FileInf build(){return  new FileInf();}

    public FileInf()
    {
    }

    public void copy(FileInf f){
        this.id=f.id;
        this.pid=f.pid;
        this.pidRoot=f.pidRoot;
        this.fdTask=f.fdTask;
        this.fdChild=f.fdChild;
        this.uid=f.uid;
        this.nameLoc=f.nameLoc;
        this.nameSvr=f.nameSvr;
        this.pathLoc=f.pathLoc;
        this.pathSvr=f.pathSvr;
        this.pathRel=f.pathRel;
        this.md5=f.md5;
        this.lenLocSec=f.lenLocSec;
        this.lenLoc=f.lenLoc;
        this.sizeLoc=f.sizeLoc;
        this.offset=f.offset;
        this.lenSvr=f.lenSvr;
        this.perSvr=f.perSvr;
        this.complete=f.complete;
        this.deleted=f.deleted;
        this.scaned=f.scaned;
        this.blockIndex=f.blockIndex;
        this.blockOffset=f.blockOffset;
        this.blockCount=f.blockCount;
        this.blockSize=f.blockSize;
        this.object_id=f.object_id;
        this.object_key=f.object_key;
        this.etag=f.etag;
        this.encrypt=f.encrypt;
    }

    @DataBaseAttribute(name="f_id")
    public String id="";
    @DataBaseAttribute(name="f_pid")
    public String pid="";
    @DataBaseAttribute(name="f_pidRoot")
    public String pidRoot="";
    /**	 * 表示当前项是否是一个文件夹项。	 */
    @DataBaseAttribute(name="f_fdTask")
    public boolean fdTask=false;
    //	/// 是否是文件夹中的子文件
    @DataBaseAttribute(name="f_fdChild")
    public boolean fdChild=false;
    /**	 * 用户ID。与第三方系统整合使用。	 */
    @DataBaseAttribute(name="f_uid")
    public int uid=0;
    @DataBaseAttribute(name="f_nameLoc")
    /**	 * 文件在本地电脑中的名称	 */
    public String nameLoc="";
    /**	 * 文件在服务器中的名称。	 */
    @DataBaseAttribute(name="f_nameSvr")
    public String nameSvr="";
    /**	 * 文件在本地电脑中的完整路径。示例：D:\Soft\QQ2012.exe	 */
    @DataBaseAttribute(name="f_pathLoc")
    public String pathLoc="";
    /**	 * 文件在服务器中的完整路径。示例：F:\\ftp\\uer\\md5.exe	 */
    @DataBaseAttribute(name="f_pathSvr")
    public String pathSvr="";
    /**	 * 文件在服务器中的相对路径。示例：/www/web/upload/md5.exe	 */
    @DataBaseAttribute(name="f_pathRel")
    public String pathRel="";
    /**	 * 文件MD5	 */
    @DataBaseAttribute(name="f_md5")
    public String md5="";
    /**	 * 数字化的文件长度。以字节为单位，示例：120125	 */
    @DataBaseAttribute(name="f_lenLoc")
    public long lenLoc=0;
    /// <summary>
    /// 本地文件加密后的大小
    /// </summary>
    @DataBaseAttribute(name="f_lenLocSec")
    public long lenLocSec = 0;
    /**	 * 格式化的文件尺寸。示例：10.03MB	 */
    @DataBaseAttribute(name="f_sizeLoc")
    public String sizeLoc="";
    /**	 * 文件续传位置。	 */
    public long offset=0;
    /**	 * 已上传大小。以字节为单位	 */
    @DataBaseAttribute(name="f_lenSvr")
    public long lenSvr=0;
    /**	 * 已上传百分比。示例：10%	 */
    @DataBaseAttribute(name="f_perSvr")
    public String perSvr="0%";
    @DataBaseAttribute(name="f_complete")
    public boolean complete=false;
    @DataBaseAttribute(name="f_time")
    public Date time = new Date();
    @DataBaseAttribute(name="f_deleted")
    public boolean deleted=false;
    /**	 * 是否已经扫描完毕，提供给大型文件夹使用，大型文件夹上传完毕后开始扫描。	 */
    @DataBaseAttribute(name="f_scan")
    public boolean scaned=false;
    //块索引，基于1
    @DataBaseAttribute(name="f_blockIndex")
    public int blockIndex=0;
    @DataBaseAttribute(name="f_blockOffset")
    public long blockOffset=0;
    /// <summary>
    /// 块总数
    /// </summary>
    @DataBaseAttribute(name="f_blockCount")
    public int blockCount = 0;
    /// <summary>
    /// 块大小
    /// </summary>
    @DataBaseAttribute(name="f_blockSize")
    public int blockSize = 0;

    //object.id，用于第三方存储的对象ID
    public String object_id="";

    @DataBaseAttribute(name="f_object_key")
    public String object_key="";
    //
    public String etag="";
    /// <summary>
    /// 文件是否加密
    /// </summary>
    @DataBaseAttribute(name="f_encrypt")
    public boolean encrypt = false;

    /// <summary>
    /// 计算文件加密后的大小，16字节对齐
    /// </summary>
    public void calLenLocSec() {
        long a = this.lenLoc % 16;
        this.lenLocSec = this.lenLoc + (16 - (a > 0 ? a : 16));
    }

    public String schemaFile() {
        return this.parentDir().concat("/schema.txt");
    }

    /**
     * 生成AWS S3文件key
     * D:\Soft\guid\QQ.exe => /guid/QQ.exe
     * @return
     */
    public String S3Key() {
        //格式 /guid/QQ.exe
        String key = PathTool.combin("", this.id);
        key = PathTool.combin(key, this.nameLoc);
        return key;
    }

    /**
     * 生成OBS key
     * D:\Soft\guid\QQ.exe => guid/QQ.exe
     * @return
     */
    public String ObsKey(){
        //格式 guid/QQ.exe
        String key = PathTool.combin(this.id, this.nameLoc);
        return key;
    }

    public String getObjectKey(){
        //Minio key => /dir/filename
        if(ConfigReader.storageType()== StorageType.Minio)return this.S3Key();
        else if(
                //oss key => dir/filename
                ConfigReader.storageType() == StorageType.OBS||
                ConfigReader.storageType() == StorageType.OSS||
                ConfigReader.storageType() == StorageType.COS
        )
            return this.ObsKey();
        return  this.object_id;
    }

    /**
     * 返回AWS s3，ETag保存文件
     * 路径：dir/guid/etags.txt
     * @return
     */
    public String ETagsFile() {
        String f = PathTool.combin(this.parentDir(),this.id);
        f = PathTool.combin(f,"etags.txt");
        return f;
    }

    public String parentDir()
    {
        File f = new File(this.pathSvr);
        return f.getParent().replace('\\', '/');
    }

    public void saveScheme()
    {
        //仅保留第一块
        if (this.blockIndex != 1) return;
        //仅保存子文件数据
        if (StringUtils.isEmpty(this.pid) ) return;

        FolderSchema fs = new FolderSchema();
        this.calLenLocSec();//自动计算文件加密后的大小
        fs.addFile(this);
    }

    /**
     * 保存块ID信息
     * 路径：
     * D:/Soft/guid/etags.txt
     */
    public void saveEtags() {
        FileEtag fe = new FileEtag();
        fe.saveTags(this);
    }

    public void saveEtagsObs(){
        FileEtag fe = new FileEtag();
        fe.saveTags(this);
    }

    /**
     * <CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
     <Part>
     <ChecksumCRC32>string</ChecksumCRC32>
     <ChecksumCRC32C>string</ChecksumCRC32C>
     <ChecksumSHA1>string</ChecksumSHA1>
     <ChecksumSHA256>string</ChecksumSHA256>
     <ETag>string</ETag>
     <PartNumber>integer</PartNumber>
     </Part>
     ...
     </CompleteMultipartUpload>

     * @return
     */
    public String etags() {
        String xml = "";
        List<FileInf> files = new ArrayList<FileInf>();
        //加载/guid/etags.txt
        File f = new File(this.ETagsFile());
        BufferedReader br;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(f),"UTF-8"));
            String line = null;
            Gson g = new Gson();
            Map<Integer, Boolean> blocks = new HashMap<Integer, Boolean>();
            while( (line = br.readLine() )!=null )
            {
                FileInf block = g.fromJson(line, FileInf.class);
                //防止重复添加块信息
                if(!blocks.containsKey(block.blockIndex))
                {
                    files.add(block);
                    blocks.put(block.blockIndex,true);
                }
            }
            br.close();

            org.dom4j.Document dom = DocumentHelper.createDocument();
            Element root = dom.addElement("CompleteMultipartUpload");
            for(FileInf i : files)
            {
                Element part = root.addElement("Part");
                part.addElement("ETag").addText(i.etag);
                part.addElement("PartNumber").addText( String.valueOf( i.blockIndex ));
            }
            xml = root.asXML();

        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return xml;
    }

    /**
     * 获取华为对象存储
     * @return
     */
    public List<PartEtag> etagsObs(){
        List<PartEtag> parts = new ArrayList<PartEtag>();
        List<FileInf> files = new ArrayList<FileInf>();
        //加载/guid/etags.txt
        File f = new File(this.ETagsFile());
        BufferedReader br;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(f),"UTF-8"));
            String line = null;
            Gson g = new Gson();
            Map<Integer, Boolean> blocks = new HashMap<Integer, Boolean>();
            while( (line = br.readLine() )!=null )
            {
                FileInf block = g.fromJson(line, FileInf.class);
                //防止重复添加块信息
                if(!blocks.containsKey(block.blockIndex))
                {
                    files.add(block);
                    blocks.put(block.blockIndex,true);
                }
            }
            br.close();

            for(FileInf i : files)
            {
                PartEtag part = new PartEtag();
                part.setPartNumber(i.blockIndex);
                part.setEtag(i.etag);
                parts.add(part);
            }

        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return parts;
    }

    public List<PartETag> etagsOSS(){
        List<PartETag> parts = new ArrayList<PartETag>();
        List<FileInf> files = new ArrayList<FileInf>();
        //加载/guid/etags.txt
        File f = new File(this.ETagsFile());
        BufferedReader br;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(f),"UTF-8"));
            String line = null;
            Gson g = new Gson();
            Map<Integer, Boolean> blocks = new HashMap<Integer, Boolean>();
            while( (line = br.readLine() )!=null )
            {
                FileInf block = g.fromJson(line, FileInf.class);
                //防止重复添加块信息
                if(!blocks.containsKey(block.blockIndex))
                {
                    files.add(block);
                    blocks.put(block.blockIndex,true);
                }
            }
            br.close();

            for(FileInf i : files)
            {
                PartETag part = new PartETag(i.blockIndex,i.etag);
                parts.add(part);
            }

        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return parts;
    }

    public List<com.qcloud.cos.model.PartETag> etagsCos(){

        List<com.qcloud.cos.model.PartETag> parts = new ArrayList<com.qcloud.cos.model.PartETag>();
        List<FileInf> files = new ArrayList<FileInf>();
        //加载/guid/etags.txt
        File f = new File(this.ETagsFile());
        BufferedReader br;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(f),"UTF-8"));
            String line = null;
            Gson g = new Gson();
            Map<Integer, Boolean> blocks = new HashMap<Integer, Boolean>();
            while( (line = br.readLine() )!=null )
            {
                FileInf block = g.fromJson(line, FileInf.class);
                //防止重复添加块信息
                if(!blocks.containsKey(block.blockIndex))
                {
                    files.add(block);
                    blocks.put(block.blockIndex,true);
                }
            }
            br.close();

            for(FileInf i : files)
            {
                com.qcloud.cos.model.PartETag part = new com.qcloud.cos.model.PartETag(i.blockIndex,i.etag);
                parts.add(part);
            }

        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return parts;
    }

    public String formatSize(long byteCount)
    {
        return PathTool.BytesToString(byteCount);
    }
}